<?php
namespace App\Third\Game;
use Illuminate\Support\Facades\Config;

class SocketClient{

	protected $_address = '';
	protected $_port = 0;
    protected $socket = null;

	public function __construct($address, $port){
		$address && $this->_address = $address;
		$port && $this->_port = $port;
	}

	public function Send($argc = []){

        try {
            $address = $this->_address;
    		$port = $this->_port;
    
    		$param = $argc ?: [];
    		// for($i=2;$i<$argc;$i++)
    		// {
    		//     list($k,$v)=explode("=",$argv[$i]);
    		//     $param[$k]=$v;
    		// }
    		$buf=json_encode($param,0xffffffff);//$argv[2];
            if (!$param['msgid']) {
    		    self::__log_error($buf."\n");      
            }
    
    		//$data=pack("n",strlen($buf)+2+2).$buf;
    		//$data = pack("n",strlen($buf)+2+2).pack("n",$param['msgid']).$buf;
            $data = pack("N",strlen($buf)+4+4).pack("N", $param['msgid']).$buf;
    		$this->socket  = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    
    		$this->set_option($this->socket);
    
    		$conn = @socket_connect($this->socket, $address, $port) ;
                \Log::debug('socket connection ', [$address, $port, $conn]);
            
            if (!$conn) {
                \Log::error('socket connection ', [$address, $port,$conn ,socket_strerror(socket_last_error($this->socket)) ]);
                return ;
            }
    
    		$n=socket_write($this->socket,$data,strlen($data));

		   return $this->ReadHttpReponse();

        } catch (\Exception $e) {
		    self::__log_error("socket_connection failed: reason: " . socket_strerror(socket_last_error($this->socket)) . $e->getMessage(). " connection info {$address}:{$port} \n");
        }

	}

	public function ReadHttpReponse()
	{
		//sleep(1);
		$length_data = socket_read($this->socket, 4);

		if (false === ($length_data)) {
			\Log::error('socket_read ', [socket_strerror(socket_last_error($this->socket)) ]);
			return ;
		}
		/* $length_data=socket_read($socket,2); */
		$result=unpack("N",$length_data);
		$length=$result[1];

		// \Log::info('socket_read ', ["json_string.length=$length\n"]);

		$step_max = 5;
		$json_string = "";
		
		$left_len = $length-4;
		while ($step_max > 0 ) {
			
			$left_len -= strlen($json_string);
			if ( $left_len <= 0 ) {
				break;
			}
			$json_string .= socket_read($this->socket, $left_len);

			$step_max--;
		}
		
		$json_string = substr($json_string,4);
		
		$res = json_decode($json_string, true);
		\Log::info('socket_read ', [$length]);
		return $res;
	}

    public function close(&$socket, $us = 10000){
        !$socket && $socket = $this->socket;
		usleep($us);
        socket_close($socket);
    }

	protected function set_option(&$socket){
        !$socket && $socket = $this->socket;
		socket_set_option(
			$socket,
			SOL_SOCKET,  // socket level
			SO_SNDTIMEO, // timeout option
            [
				"sec"	=>2, // Timeout in seconds
				"usec"	=>0,  // I assume timeout in microseconds
			]
		);
        socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>1, "usec"=>0 ) );
        return $socket;
	}

	protected static function __log_error($s, $domain = null){
		$debug= Config::get("app.debug");
		if(empty($debug)) return;
		file_put_contents("/tmp/socket.log", $domain .':'.date("Y-m-d H:i:s").':'. $s, 8);
	}
}
